package me.chenjp.tracker.service;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import me.chenjp.tracker.core.enums.StatusEnum;
import me.chenjp.tracker.core.utils.JwtCache;
import me.chenjp.tracker.entity.User;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.Date;
import java.util.UUID;

/**
 * @author: Chenjp
 * @description: 这个人很懒, 没有留下任何注释
 * @create: 2019-05-03 13:05
 */
@Service
public class JwtServiceImpl implements JwtService {

    @Value("${jwt.secret}")
    private String jwtSecret;

    @Resource
    private JwtCache<Integer, String> jwtCache;

    @Resource
    private UserService userService;

    @Override
    public String createJwt(Integer uid, String role, String name) {
        Date now = new Date();
        String token = Jwts.builder()
                .setSubject(uid.toString())
                .setAudience("WEB")
                .setIssuedAt(now)
                .setId(UUID.randomUUID().toString().replaceAll("-", "").toLowerCase())
                .claim("role", role)
                .claim("name", name)
                .setExpiration(DateUtils.addMonths(now, 1))
                .signWith(SignatureAlgorithm.HS256, jwtSecret).compact();

        jwtCache.put(uid, token);

        return token;
    }

    @Override
    public void removeTokenFromJwtCache(Integer uid) {
        jwtCache.remove(uid);
    }

    @Override
    public Integer getUid(String token) {
        Claims claims = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody();
        return Integer.parseInt(claims.getSubject());
    }

    @Override
    public void verify(String token) {
        Integer uid = getUid(token);
        String cacheToken = jwtCache.get(uid);
        if (cacheToken == null) {
            // 先在本地缓存中获取，若没有命中，则去数据库查找
            User user = userService.selectByKey(uid).orElse(null);
            Assert.notNull(user, "用户不存在");
            Assert.isTrue(!StatusEnum.NORMAL.getName().equals(user.getStatus()), "用户不存在");
            cacheToken = user.getToken();

            Assert.notNull(cacheToken, "登录已过期，请重新登录");
            Assert.isTrue(cacheToken.equals(token), "登录已过期，请重新登录");
            // 把数据库中拿到的 token 放到缓存
            jwtCache.put(uid, token);
        } else {
            Assert.isTrue(token.equals(cacheToken), "登录已过期，请重新登录");
        }

        // 是否已过期
        Assert.isTrue(getExpireTime(token).after(new Date()), "登录已过期，请重新登录");
    }

    private Date getExpireTime(String token) {
        Claims claims = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody();
        return claims.getExpiration();
    }

    @Override
    public String getUserRole(String token) {
        Claims claims = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody();
        return claims.getOrDefault("role", "").toString();
    }

    @Override
    public String getName(String token) {
        return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody().getOrDefault("name", "").toString();
    }
}

